home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 September / Macworld (1998-09).dmg / Shareware World / Info / For Developers / MacZoop 1.8.3 / Required Classes / Z Sources / ZWindow.cpp < prev    next >
Text File  |  1998-07-10  |  61KB  |  2,404 lines

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"         
  5. *
  6. *
  7. *
  8. *            ZWindow.cpp            -- the window object
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *            14/11/96- modified to support undo and printing.
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "ZWindow.h"
  23. #include    "MacZoop.h"
  24. #include    "ZEventHandler.h"
  25. #include    "ZUndoTask.h"
  26. #include    "ProjectSettings.h"
  27.  
  28. #if APPEARANCE_MGR_AWARE
  29.     #include    "Appearance.h"
  30. #endif
  31.  
  32.  
  33. #if _WPOS_WINDOW_PLACEMENT
  34. #include    "ZResourceFile.h"
  35. #endif
  36.  
  37.  
  38. static short CalculateOffsetAmount(    short idealStartPoint,
  39.                                     short idealEndPoint,
  40.                                     short idealOnScreenStartPoint,
  41.                                     short idealOnScreenEndPoint,
  42.                                     short screenEdge1,
  43.                                     short screenEdge2 );
  44.                                     
  45. static pascal OSErr    ZWTrackingHandler( DragTrackingMessage theMsg, WindowPtr theWindow, void* refCon,
  46.                                         DragReference theDrag );
  47. static pascal OSErr    ZWDropHandler( WindowPtr theWindow, void* refCon, DragReference theDrag );
  48.  
  49.  
  50.  
  51. static DragTrackingHandlerUPP    gDragTrackProc      = NewDragTrackingHandlerProc( ZWTrackingHandler );
  52. static DragReceiveHandlerUPP    gDragReceiveProc = NewDragReceiveHandlerProc( ZWDropHandler );
  53.  
  54. CLASSCONSTRUCTOR( ZWindow );
  55.  
  56. /*------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  57.  
  58. ZWindow::ZWindow( ZCommander* aBoss, const short windowID )
  59.     : ZCommander( aBoss )
  60. {
  61.     classID = CLASS_ZWindow;
  62.     
  63.     windID = windowID;
  64.     macWindow = NULL;
  65.     dirty = FALSE;
  66.     isNamed = FALSE;
  67.     stationeryFile = FALSE;
  68.     macFile.vRefNum = kNoFile;
  69.     macFType = 0;
  70.     printable = FALSE;
  71.     isPrinting = FALSE;
  72.     floating = FALSE;
  73.     disableAutoClose = FALSE;
  74.     SetRect( &zoomSource, 0, 0, 0, 0 );
  75.     
  76.     // initial sizeRect is set to an arbitrary size
  77.     
  78.     SetRect( &sizeRect,120 ,90 ,2000, 2000 );
  79. }
  80.  
  81.  
  82. ZWindow::ZWindow()
  83.     : ZCommander()
  84. {
  85.     classID = CLASS_ZWindow;
  86.  
  87.     windID = 0;
  88.     macWindow = NULL;
  89.     dirty = FALSE;
  90.     isNamed = FALSE;
  91.     stationeryFile = FALSE;
  92.     macFile.vRefNum = kNoFile;
  93.     macFType = 0;
  94.     printable = FALSE;
  95.     isPrinting = FALSE;
  96.     floating = FALSE;
  97.     disableAutoClose = FALSE;
  98.     SetRect( &zoomSource, 0, 0, 0, 0 );
  99.     SetRect( &sizeRect, 0, 0, 0, 0 );
  100. }    
  101.  
  102. /*------------------------------***  DESTRUCTOR  ***---------------------------------*/
  103.  
  104. ZWindow::~ZWindow()
  105. {
  106.     // set the current port to something else
  107.     
  108.     if ( FrontWindow())
  109.         SetPort( FrontWindow()); 
  110.     
  111.     // if the application has an undo task pertaining to this window, delete it.
  112.     
  113.     ZUndoTask*    curTask = gApplication->GetUndoTask();
  114.     
  115.     if ( curTask && ( curTask->GetUndoTarget() == this ))
  116.         gApplication->SetTask( NULL );
  117.     
  118.     // wMgr no longer needs us
  119.         
  120.     gWindowManager->RemoveWindow( this );
  121.     
  122.     if ( macWindow )
  123.     {
  124.         #if _AUTO_WPOS_FOR_FLOATERS
  125.         
  126.         if ( floating )
  127.             SavePosition();
  128.         
  129.         #endif
  130.         
  131.         if ( MacHasDM())
  132.             RemoveDragHandlers();
  133.  
  134.         DisposeWindow( macWindow );
  135.     }
  136.     
  137.     macWindow = NULL;
  138. }
  139.  
  140.  
  141. /*--------------------------------***  INITZWINDOW  ***---------------------------------*/
  142. /*    
  143.  
  144. initialise this object. By default, this just makes the window
  145. ----------------------------------------------------------------------------------------*/
  146.  
  147. void    ZWindow::InitZWindow()
  148. {
  149.     MakeMacWindow( windID );
  150.     
  151.     if ( MacHasDM())
  152.         InstallDragHandlers();
  153.  
  154.     // tell the window manager of our existence. This must be done after the
  155.     // full build of the mac window since the window manager needs to get
  156.     // information from it. Thus if you override this method, make sure you
  157.     // make the same call.
  158.     
  159.     gWindowManager->AddWindow( this );
  160.     
  161.     #if _AUTO_WPOS_FOR_FLOATERS
  162.     
  163.     if ( floating )
  164.         RestorePosition();
  165.     
  166.     #endif
  167. }
  168.  
  169.  
  170. /*------------------------------***  MAKEMACWINDOW  ***---------------------------------*/
  171. /*    
  172.  
  173. create the macintosh window that this object looks after
  174. ----------------------------------------------------------------------------------------*/
  175.  
  176. void    ZWindow::MakeMacWindow( const short windID )
  177. {
  178.     if ( gMacInfo.supportsColour )
  179.         FailNIL( macWindow = GetNewCWindow( windID, NULL, NULL ));
  180.     else
  181.         FailNIL( macWindow = GetNewWindow( windID, NULL, NULL ));
  182.         
  183.     // so we can identify the window, we set the windowKind to a special value. The refCon
  184.     // contains the object reference so we can freely locate the object from the window and
  185.     // vice versa. Your application must not touch the refCon- add members to your window
  186.     // objects instead.
  187.     
  188.     ((WindowPeek) macWindow)->windowKind = IS_ZWINDOW_KIND;
  189.     SetWRefCon( macWindow, (long) this );
  190.     
  191.     // what WDEF are we using for this window? If it's one of the known "floater" types,
  192.     // then we should set the floating flag automatically- one less thing the programmer
  193.     // needs to worry about, and will work for the common cases.
  194.     
  195.     WindTemplateHdl        wTH = (WindTemplateHdl) GetResource( 'WIND', windID );
  196.     
  197.     if ( wTH )
  198.     {
  199.         // the system floater has a proc of 124. The commonly used "Infinity" windoid
  200.         // has a proc of 128.
  201.         
  202.         short    pID = (*wTH)->procID / 16;
  203.         
  204.         // with appearance manager, the WDEF IDs for floating windows are 66 & 67
  205.         
  206.         #if APPEARANCE_MGR_AWARE
  207.         
  208.         if ( gMacInfo.hasAppearanceMgr )
  209.             floating |= (     pID == kWindowUtilityDefProcResID ||
  210.                             pID == kWindowUtilitySideTitleDefProcResID );
  211.         
  212.         #endif
  213.         
  214.         floating |= (    pID == kFloatingWindowDefinition ||
  215.                         pID == kInfinityWindoidDefinition );
  216.  
  217.         ReleaseResource((Handle) wTH );
  218.     }
  219.     
  220.     // allocate a unique title. This we'll base on the current title
  221.     // (which should be "untitled"), with an appended digit to ensure uniqueness
  222.     
  223.     Str255    wTitle;
  224.     
  225.     GetWTitle( macWindow, wTitle );
  226.     if ( gWindowManager->GetUniqueUntitledName( wTitle ))
  227.         SetWTitle( macWindow, wTitle );
  228.         
  229.     CopyPString( wTitle, macFile.name );
  230.         
  231.     // if appearance savvy, make a root control for the window so stuff can be
  232.     // embedded into it easily.
  233.     
  234.     #if APPEARANCE_MGR_AWARE
  235.     
  236.     if ( gMacInfo.hasAppearanceMgr )
  237.     {
  238.         ControlHandle    rc;
  239.         
  240.         FailOSErr( CreateRootControl( macWindow, &rc ));
  241.     }
  242.     
  243.     #endif
  244. }
  245.  
  246. /*------------------------------***  MAKEMACWINDOW  ***---------------------------------*/
  247.  
  248. void        ZWindow::MakeMacWindow( Rect* aRect, Str255 title, Boolean visible, short varCode, Boolean hasCloseBox, void* userData )
  249. {
  250.     if ( gMacInfo.supportsColour )
  251.         FailNIL( macWindow = NewCWindow( NULL, aRect, title, visible, varCode, NULL, hasCloseBox, 0 ));
  252.     else
  253.         FailNIL( macWindow = NewWindow( NULL, aRect, title, visible, varCode, NULL, hasCloseBox, 0 ));
  254.  
  255.     ((WindowPeek) macWindow)->windowKind = IS_ZWINDOW_KIND;
  256.     SetWRefCon( macWindow, (long) this );
  257.  
  258.     CopyPString( title, macFile.name );
  259.         
  260.     // if appearance savvy, make a root control for the window so stuff can be
  261.     // embedded into it easily.
  262.     
  263.     #if APPEARANCE_MGR_AWARE
  264.     
  265.     if ( gMacInfo.hasAppearanceMgr )
  266.     {
  267.         ControlHandle    rc;
  268.         
  269.         FailOSErr( CreateRootControl( macWindow, &rc ));
  270.     }
  271.     
  272.     #endif
  273. }
  274.  
  275. #pragma mark -
  276.  
  277. /*----------------------------------***  ACTIVATE  ***----------------------------------*/
  278. /*    
  279.  
  280. this window is becoming active
  281. ----------------------------------------------------------------------------------------*/
  282.  
  283. void    ZWindow::Activate()
  284. {
  285.     // the window is activated. If appearance mgr savvy, activate root control:
  286.     
  287.     #if APPEARANCE_MGR_AWARE
  288.     
  289.     if ( gMacInfo.hasAppearanceMgr )
  290.     {
  291.         OSErr            theErr;
  292.         ControlHandle     rc;
  293.         
  294.         theErr = GetRootControl( macWindow, &rc );
  295.         
  296.         if ( theErr == noErr )
  297.             FailOSErr( ActivateControl( rc ));
  298.     }
  299.     else
  300.         DrawGrow();
  301.     
  302.     #else
  303.     
  304.     DrawGrow();
  305.     
  306.     #endif
  307. }
  308.  
  309.  
  310. /*---------------------------------***  DEACTIVATE  ***---------------------------------*/
  311. /*    
  312.  
  313. this window is becoming inactive
  314. ----------------------------------------------------------------------------------------*/
  315.  
  316. void    ZWindow::Deactivate()
  317. {
  318.     #if APPEARANCE_MGR_AWARE
  319.     
  320.     if ( gMacInfo.hasAppearanceMgr )
  321.     {
  322.         OSErr            theErr;
  323.         ControlHandle     rc;
  324.         
  325.         theErr = GetRootControl( macWindow, &rc );
  326.         
  327.         if ( theErr == noErr )
  328.             FailOSErr( DeactivateControl( rc ));
  329.     }
  330.     else
  331.         DrawGrow();
  332.     
  333.     #else
  334.     
  335.     DrawGrow();
  336.     
  337.     #endif
  338. }
  339.  
  340.  
  341. /*------------------------------------***  FOCUS  ***-----------------------------------*/
  342. /*    
  343.  
  344. make this window the current port ready for drawing or clicking
  345. ----------------------------------------------------------------------------------------*/
  346.  
  347. void    ZWindow::Focus()
  348. {
  349.     SetGWorld((CGrafPtr) macWindow, GetMainDevice());
  350.     SetOrigin( 0, 0 );
  351.     ClipRect( &macWindow->portRect );
  352. }
  353.  
  354.  
  355. /*--------------------------------***  POSTREFRESH  ***---------------------------------*/
  356. /*    
  357.  
  358. invalidate the window contents so that it gets redrawn on the next update
  359. ----------------------------------------------------------------------------------------*/
  360.  
  361. void    ZWindow::PostRefresh()
  362. {
  363.     Focus();
  364.     InvalRect( &macWindow->portRect );
  365. }
  366.  
  367.  
  368. /*------------------------------***  PERFORMUPDATE  ***---------------------------------*/
  369. /*    
  370.  
  371. handle an update event. This is normally called from the event handler object, but you
  372. can call it directly for special purposes if you know there is an update that needs
  373. handling.
  374. ----------------------------------------------------------------------------------------*/
  375.  
  376. void    ZWindow::PerformUpdate()
  377. {
  378.     GrafPtr        savePort;
  379.     
  380.     GetPort( &savePort );
  381.     Focus();
  382.     
  383.     // start the update sequence
  384.     
  385.     BeginUpdate( macWindow );
  386.     
  387.     if ( ! EmptyRgn( macWindow->visRgn ))
  388.     {
  389.         try
  390.         {
  391.             Draw();
  392.         }
  393.         catch( OSErr err )
  394.         {
  395.             EndUpdate( macWindow );
  396.             SetPort( savePort );
  397.             throw err;
  398.         }
  399.     }
  400.     EndUpdate( macWindow );
  401.     SetPort( savePort );
  402. }
  403.  
  404. /*------------------------------------***  DRAW  ***------------------------------------*/
  405. /*    
  406.  
  407. draw the contents of this window. This is the main draw dispatcher.
  408. ----------------------------------------------------------------------------------------*/
  409.  
  410. void    ZWindow::Draw()
  411. {
  412.     // if we are growable, we should clip out the scrollbar areas otherwise
  413.     // the DrawContent call may erase the growbox, etc
  414.     
  415.     short    v = GetWVariant(macWindow);
  416.     
  417.     if (v == documentProc || v == zoomDocProc)
  418.     {
  419.         Rect    r = macWindow->portRect;
  420.         
  421.         r.right -= kStdScrollbarWidth;
  422.         r.bottom -= kStdScrollbarWidth;
  423.         ClipRect( &r );
  424.     }
  425.     DrawContent();
  426.     
  427.     SetOrigin( 0, 0 );
  428.     ClipRect( &macWindow->portRect );        
  429.     DrawControls( macWindow );
  430.  
  431.     DrawGrow();
  432. }
  433.  
  434.  
  435. /*-------------------------------***  DRAWCONTENT  ***----------------------------------*/
  436. /*    
  437.  
  438. draw the content area of this window- this is what will draw the meaningful part
  439. ----------------------------------------------------------------------------------------*/
  440.  
  441. void    ZWindow::DrawContent()
  442. {
  443.     if (! isPrinting)
  444.         EraseRect( &macWindow->portRect );
  445. }
  446.  
  447.  
  448. /*----------------------------***  SETDEFAULTCOLOURS  ***-------------------------------*/
  449. /*    
  450. restores the window's default colours after drawing code may have changed it.
  451. ----------------------------------------------------------------------------------------*/
  452.  
  453. void    ZWindow::SetDefaultColours()
  454. {
  455.     Focus();
  456.     ForeColor( blackColor );
  457.     
  458.     if ( IsColourPort( macWindow ))
  459.     {
  460.         AuxWinHandle    aw;
  461.         RGBColor        rgb = { -1, -1, -1 };
  462.         
  463.         GetAuxWin( macWindow, &aw );
  464.         
  465.         if ( aw )
  466.             rgb = (*(*aw)->awCTable)->ctTable[0].rgb;
  467.     
  468.         RGBBackColor( &rgb );
  469.     }
  470.     else
  471.         BackColor( whiteColor );
  472. }    
  473.  
  474. /*---------------------------------***  DRAWGROW  ***-----------------------------------*/
  475. /*    
  476.  
  477. draw the grow icon if the window type indicates this is appropriate
  478. ----------------------------------------------------------------------------------------*/
  479.  
  480. void    ZWindow::DrawGrow()
  481. {
  482.     if ( macWindow )
  483.     {
  484.         short    v = GetWVariant( macWindow );
  485.         
  486.         if ( v == documentProc || v == zoomDocProc )
  487.         {
  488.             Rect    r = macWindow->portRect;
  489.             
  490.             r.left = r.right - kStdScrollbarWidth;
  491.             r.top = r.bottom - kStdScrollbarWidth;
  492.             
  493.             ClipRect( &r );
  494.             DrawGrowIcon( macWindow );
  495.         }
  496.     }
  497. }
  498.  
  499.  
  500. #pragma mark -
  501.  
  502. /*---------------------------------***  CALCPAGES  ***----------------------------------*/
  503. /*    
  504.  
  505. compute the pagination for printing. By default this divides the contect rect up to be
  506. tiled across the paper rect, horizontal major order. Override for other methods
  507. ----------------------------------------------------------------------------------------*/
  508.  
  509. void    ZWindow::CalcPages( const Rect& paperRect, short* pagesH, short* pagesV )
  510. {
  511.     Rect    cr;
  512.     short    pWidth, pHeight, cWidth, cHeight;
  513.     
  514.     GetBounds( &cr );
  515.     
  516.     pWidth = paperRect.right - paperRect.left;
  517.     pHeight = paperRect.bottom - paperRect.top;
  518.     
  519.     cWidth = cr.right - cr.left;
  520.     cHeight = cr.bottom - cr.top;
  521.     
  522.     *pagesH = (cWidth / pWidth) + 1;
  523.     *pagesV = (cHeight / pHeight) + 1;
  524. }
  525.  
  526. /*-------------------------------***  PRINTONEPAGE  ***---------------------------------*/
  527. /*    
  528. draw the requested page (numbered according to the pagination you set up) to the current
  529. port, which will be a printing port when called. By default this manipulates the origin
  530. and draws the content, suitably clipped, to the port. Override for other behaviour.
  531. ----------------------------------------------------------------------------------------*/
  532.  
  533. void    ZWindow::PrintOnePage( const short pageNum, const Rect& paperRect )
  534. {
  535.     Rect    pr;
  536.     short    hp, vp, dH, dV;
  537.     
  538.     // calculate the printing area
  539.     
  540.     CalcPages( paperRect, &hp, &vp );
  541.     pr = paperRect;
  542.     
  543.     dH = paperRect.right  * ((pageNum - 1) % hp);
  544.     dV = paperRect.bottom * ((pageNum - 1) / hp);
  545.     
  546.     OffsetRect( &pr, dH, dV );
  547.     
  548.     // make sure that the text & pen attributes in the window and printing port match
  549.     // in case the DrawContent routine doesn't set them as it goes.
  550.     
  551.     TextFont( macWindow->txFont );
  552.     TextSize( macWindow->txSize );
  553.     TextFace( macWindow->txFace );
  554.     TextMode( srcOr );
  555.     PenSize( macWindow->pnSize.h, macWindow->pnSize.v );
  556.     PenPat( &macWindow->pnPat );
  557.     PenMode( macWindow->pnMode );
  558.     
  559.     // draw the contents.
  560.     
  561.     SetOrigin( pr.left, pr.top );
  562.     ClipRect( &pr );
  563.     
  564.     DrawContent();
  565.     SetOrigin( 0, 0 );
  566. }
  567.  
  568.  
  569. /*------------------------------***  GETCONTENTRECT  ***--------------------------------*/
  570. /*    
  571.  
  572. return the content area
  573. ----------------------------------------------------------------------------------------*/
  574.  
  575. void    ZWindow::GetContentRect( Rect* contents )
  576. {
  577.     *contents = macWindow->portRect;
  578. }
  579.  
  580.  
  581.  
  582. /*-----------------------------------***  CLICK  ***------------------------------------*/
  583. /*    
  584.  
  585. the user clicked in the content area of this window. By default this does nothing.
  586. ----------------------------------------------------------------------------------------*/
  587.  
  588. void    ZWindow::Click( const Point mouse, const short modifiers )
  589. {
  590. }
  591.  
  592.  
  593. /*-----------------------------***  CLICKINSAMEPLACE  ***-------------------------------*/
  594. /*    
  595.  
  596. should this click be considered a double-click? You can override this and return TRUE if
  597. the two points are to be considered in the same place for the purposes of determining
  598. a double-click. The default method always returns TRUE. The points passed are in the
  599. window's LOCAL coordinates.
  600.  
  601. ----------------------------------------------------------------------------------------*/
  602.  
  603. Boolean    ZWindow::ClickInSamePlace( const Point click1, const Point click2 )
  604. {
  605.     return TRUE;
  606. }
  607.  
  608.  
  609. /*-------------------------------***  ADJUSTCURSOR  ***---------------------------------*/
  610. /*    
  611.  The cursor is over this window. Set its shape according to where it is and what modifiers
  612.  are down. By default this just sets the cursor to an arrow. <mouse> is in local coords.
  613.  
  614. ----------------------------------------------------------------------------------------*/
  615.  
  616. void    ZWindow::AdjustCursor( const Point mouse, const short modifiers )
  617. {
  618.     ResumeCursorAnimation();
  619.     SetCursorShape( ARROW_CURSOR );
  620. }
  621.  
  622.  
  623. /*-------------------------------***  SETSIZERECT  ***----------------------------------*/
  624. /*    
  625.  
  626. set minimum and maximum sizes for this window
  627. ----------------------------------------------------------------------------------------*/
  628.  
  629. void    ZWindow::SetSizeRect( const Rect& szRect )
  630. {
  631.     sizeRect = szRect;
  632.     
  633.     // make sure max is not less than min:
  634.     
  635.     sizeRect.right = MAX( sizeRect.right, sizeRect.left );
  636.     sizeRect.bottom = MAX( sizeRect.bottom, sizeRect.top );
  637.     
  638.     // if the window does not conform to the size constraints, change its size so
  639.     // that it does.
  640.     
  641.     Rect        pr;
  642.     
  643.     pr = macWindow->portRect;
  644.     
  645.     if (( pr.right - pr.left ) < sizeRect.left     ||
  646.         ( pr.right - pr.left ) > sizeRect.right ||
  647.         ( pr.bottom - pr.top ) < sizeRect.top     ||
  648.         ( pr.bottom - pr.top ) > sizeRect.bottom )
  649.         SetSize( pr.right - pr.left, pr.bottom - pr.top, FALSE );
  650. }
  651.  
  652.  
  653. /*-------------------------------***  GETSIZERECT  ***----------------------------------*/
  654. /*    
  655.  
  656. get minimum and maximum sizes for this window
  657. ----------------------------------------------------------------------------------------*/
  658.  
  659. void    ZWindow::GetSizeRect( Rect* szRect )
  660. {
  661.     *szRect = sizeRect;
  662. }
  663.  
  664.  
  665. /*----------------------------------***  CLOSE  ***-------------------------------------*/
  666. /*    
  667.  
  668. we want to close this window. If it needs to be saved, do that. The user may cancel this.
  669. ----------------------------------------------------------------------------------------*/
  670.  
  671. Boolean    ZWindow::Close( const short phase )
  672. {
  673.     // the user wants to close the window. This checks the dirty flag and if dirty, asks the
  674.     // user if they want to save changes, if so, this calls save.
  675.     
  676.     // first see if we have any subsidiary windows and ask them to close
  677.     
  678.     if (! CloseSubsidiaryWindows( phase ))
  679.         return FALSE;
  680.     
  681.     // they were all closed successfully, now check this one
  682.     
  683.     short check = kCloseNoSave;
  684.     
  685.     if ( dirty )
  686.     {
  687.         #if _USE_NAV_SAVEREVERT_ALERTS
  688.         if ( gMacInfo.hasNavigationServices )
  689.         {
  690.             // use nav services version of the "save changes" dialog:
  691.             
  692.             NavDialogOptions            navOptions;
  693.             NavAskSaveChangesResult        navResult;
  694.             NavAskSaveChangesAction        navAction;
  695.             
  696.             FailOSErr( NavGetDefaultDialogOptions( &navOptions ));
  697.             
  698.             gApplication->GetName( navOptions.clientName );
  699.             GetName( navOptions.savedFileName );
  700.             
  701.             navAction = (phase == kQuitting)? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
  702.             
  703.             FailOSErr( NavAskSaveChanges(    &navOptions,
  704.                                             navAction,
  705.                                             &navResult,
  706.                                             gNavEventHandler,
  707.                                             (NavCallBackUserData) this ));
  708.                                             
  709.             // convert nav result back to MacZoop constants:
  710.             
  711.             switch ( navResult )
  712.             {
  713.                 case kNavAskSaveChangesSave:
  714.                     check = kConfirmSave;
  715.                     break;
  716.                     
  717.                 case kNavAskSaveChangesCancel:
  718.                     check = kCloseCancel;
  719.                     break;
  720.                     
  721.                 case kNavAskSaveChangesDontSave:
  722.                     check = kCloseNoSave;
  723.                     break;
  724.             }
  725.         }
  726.         else
  727.         {
  728.         #endif
  729.         
  730.         Str31    nameStr;
  731.         Str31    phaseStr;
  732.         
  733.         GetName( nameStr );
  734.         GetIndString( phaseStr, kMiscStrListID, ( phase == kRunning )? 1 : 2);
  735.         ParamText( nameStr, phaseStr, NULL, NULL );
  736.         
  737.         SetCursorShape( 0 );
  738.         check = NotifyAlert( kConfirmSaveAlertID );        // do you wish to save?
  739.         
  740.         #if _USE_NAV_SAVEREVERT_ALERTS
  741.         }
  742.         #endif
  743.         
  744.         if ( check == kConfirmSave )
  745.             if (! Save( FALSE ))                        // if so, save the file
  746.                 check = kCloseCancel;
  747.     }
  748.     
  749.     if ( check != kCloseCancel )
  750.     {
  751.         Hide();
  752.         
  753.         if ( phase == kRunning )    
  754.             SendMessage( kMsgWindowClosing, NULL );        // tell interested parties we're going away
  755.         
  756.         ForgetThis();
  757.         return TRUE;    // was closed
  758.     }
  759.     else
  760.         return FALSE;    // wasn't closed
  761. }
  762.  
  763.  
  764. /*---------------------------***  CLOSESUBSIDIARYWINDOWS  ***---------------------------*/
  765. /*    
  766. ask any windows supervised by this one to close
  767. ----------------------------------------------------------------------------------------*/
  768.  
  769. Boolean    ZWindow::CloseSubsidiaryWindows( const short phase )
  770. {
  771.     Boolean      allClosed = TRUE;
  772.     
  773.     if ( itsUnderlings )
  774.     {
  775.         // there are some commanders supervised by this object. If they are
  776.         // window objects, call their close method
  777.         
  778.         ZWindow*    w;
  779.         long        i = itsUnderlings->CountItems();
  780.         
  781.         while( i )
  782.         {
  783.             // use RTTI to make sure the object is some sort of window
  784.             
  785.             w = dynamic_cast<ZWindow*>(itsUnderlings->GetObject( i-- ));
  786.             
  787.             if (w)
  788.             {
  789.                 // yes it is, so ask it to close
  790.                 
  791.                 if (! w->Close( phase ))
  792.                 {
  793.                     // if it didn't close, then abandon the closure sequence
  794.                     
  795.                     allClosed = FALSE;
  796.                     break;
  797.                 }
  798.             }
  799.         }
  800.     }
  801.     
  802.     return allClosed;
  803. }
  804.  
  805.  
  806.  
  807. /*-----------------------------------***  HIDE  ***-------------------------------------*/
  808. /*    
  809.  
  810. make this window invisible
  811.  
  812. ----------------------------------------------------------------------------------------*/
  813.  
  814. void    ZWindow::Hide()
  815. {
  816.     Boolean wasVis = IsVisible();
  817.     
  818.     gWindowManager->HideWindow( this );
  819.     
  820.     if ( wasVis )
  821.         gWindowManager->ZoomWindowClosed( this );
  822. }
  823.  
  824.  
  825. /*-----------------------------------***  SHOW  ***-------------------------------------*/
  826. /*    
  827.  
  828. make this window visible
  829.  
  830. ----------------------------------------------------------------------------------------*/
  831.  
  832. void    ZWindow::Show()
  833. {
  834.     gWindowManager->ShowWindow( this );
  835. }
  836.  
  837.  
  838. /*---------------------------------***  SELECT  ***-------------------------------------*/
  839. /*    
  840.  
  841. make this window the active window
  842.  
  843. ----------------------------------------------------------------------------------------*/
  844.  
  845. void    ZWindow::Select()
  846. {
  847.     gWindowManager->SelectWindow( this );
  848. }
  849.  
  850.  
  851. /*---------------------------------***  PLACEAT  ***------------------------------------*/
  852. /*    
  853.  
  854. position the window on the screen at h, v.
  855.  
  856. ----------------------------------------------------------------------------------------*/
  857.  
  858. void    ZWindow::PlaceAt( const short hGlobal, const short vGlobal )
  859. {
  860.     MoveWindow( macWindow, hGlobal, vGlobal, FALSE );
  861. }
  862.  
  863.  
  864. /*----------------------------------***  PLACE  ***-------------------------------------*/
  865. /*    
  866.  
  867. place the window in it's default location. By default this just calls the window manager's
  868. InitiallyPlace() method. Override it for special placement.
  869. ----------------------------------------------------------------------------------------*/
  870.  
  871. void    ZWindow::Place()
  872. {
  873.     gWindowManager->InitiallyPlace( this );
  874.     
  875.     if ( macFile.vRefNum != kNoFile && ! IsVisible())
  876.         RestorePosition();
  877. }
  878.  
  879.  
  880.  
  881. /*-------------------------------***  SAVEPOSITION  ***---------------------------------*/
  882. /*    
  883. save the window's position in a 'Wpos' resource. If the window has a file, it's saved
  884. there. If not, the global prefs file (if any) is used. If the id passed is 0, the windID
  885. is used as a resource ID.
  886. ----------------------------------------------------------------------------------------*/
  887.  
  888. void    ZWindow::SavePosition( short id )
  889. {
  890. #if _WPOS_WINDOW_PLACEMENT
  891.  
  892.     if ( id == 0 )
  893.         id = windID;
  894.         
  895.     ZResourceFile*    aFile = NULL;
  896.     
  897.     if ( macFile.vRefNum != kNoFile )
  898.         FailNIL( aFile = new ZResourceFile( macFile ));
  899.         
  900.     gWindowManager->SaveWindowPosition( this, aFile, id );
  901.  
  902.     if ( aFile )
  903.         ForgetObject( aFile );
  904.         
  905. #endif
  906. }
  907.  
  908.  
  909.  
  910.  
  911. /*-----------------------------***  RESTOREPOSITION  ***--------------------------------*/
  912. /*
  913.  
  914. restores the window's position from a 'WPos' resource, either in its own file or the
  915. prefs, if any. If id is 0, the windID is used to identify the resource.    
  916. ----------------------------------------------------------------------------------------*/
  917.  
  918. void    ZWindow::RestorePosition( short id )
  919. {
  920. #if _WPOS_WINDOW_PLACEMENT
  921.  
  922.     if ( id == 0 )
  923.         id = windID;
  924.         
  925.     ZResourceFile*    aFile = NULL;
  926.     
  927.     if ( macFile.vRefNum != kNoFile )
  928.         FailNIL( aFile = new ZResourceFile( macFile ));
  929.     
  930.     gWindowManager->RestoreWindowPosition( this, aFile, id );
  931.     
  932.     if ( aFile )
  933.         ForgetObject( aFile );    
  934.         
  935. #endif
  936. }
  937.  
  938.  
  939. #pragma mark -
  940.  
  941. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  942. /*    
  943.  
  944. handle commands for a window, like Save, Save As, Close, etc.
  945.  
  946. ----------------------------------------------------------------------------------------*/
  947.  
  948. void    ZWindow::HandleCommand( const long aCmd )
  949. {
  950.     EventRecord        ev;
  951.     
  952.     switch ( aCmd )
  953.     {
  954.         case kCmdClose:
  955.             gApplication->GetCurrentEvent( &ev );
  956.             
  957.             if ( ev.modifiers & optionKey )
  958.                 gApplication->CloseAll( Floats() );
  959.             else
  960.                 Close( kRunning );
  961.             break;
  962.         case kCmdSave:
  963.             Save( FALSE );
  964.             break;
  965.         case kCmdSaveAs:
  966.             Save( TRUE );
  967.             break;
  968.         case kCmdRevert:
  969.             Revert();
  970.             break;
  971.         default:
  972.             // pass other commands up to this object's boss (the app, in this case)
  973.             ZCommander::HandleCommand( aCmd );
  974.             break;
  975.     }
  976. }
  977.  
  978.  
  979. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  980.  
  981. void    ZWindow::HandleCommand( const short menuID, const short itemID )
  982. {
  983.     ZCommander::HandleCommand( menuID, itemID );
  984. }
  985.  
  986.  
  987. /*--------------------------------***  UPDATEMENUS  ***---------------------------------*/
  988. /*    
  989.  
  990. updet the menus for a window, like Save, Save As, Close, etc.
  991.  
  992. ----------------------------------------------------------------------------------------*/
  993.  
  994. void    ZWindow::UpdateMenus()
  995. {
  996.     // this enables the Close, Save and SaveAs commands.
  997.     
  998.     EventRecord        ev;
  999.     
  1000.     gApplication->GetCurrentEvent( &ev );
  1001.     
  1002.     // show "Close All" if the option key is down, else "Close"
  1003.     
  1004.     if (ev.modifiers & optionKey )
  1005.         gMenuBar->SetCommandText( kCmdClose, kMiscStrListID, 8 );
  1006.     else
  1007.         gMenuBar->SetCommandText( kCmdClose, kMiscStrListID, 9 );
  1008.     
  1009.     gMenuBar->EnableCommand( kCmdClose );
  1010.     
  1011.     if ( dirty )
  1012.     {
  1013.         gMenuBar->EnableCommand( kCmdSave );
  1014.         
  1015.         if ( isNamed )
  1016.             gMenuBar->EnableCommand( kCmdRevert );
  1017.     }
  1018.     gMenuBar->EnableCommand( kCmdSaveAs );
  1019.  
  1020.     // call the boss to enable her menus
  1021.     
  1022.     ZCommander::UpdateMenus();
  1023. }
  1024.  
  1025.  
  1026. /*-----------------------------------***  SETTASK  ***----------------------------------*/
  1027. /*    
  1028. submit an undoable task for this window. This updates the global undo task and marks the
  1029. document as dirty.
  1030. ----------------------------------------------------------------------------------------*/
  1031.  
  1032. void        ZWindow::SetTask( ZUndoTask* aTask )
  1033. {
  1034.     // if we're not dirty when the task arrives, then this must be the first task. Let it
  1035.     // know so that if the task is undone, it can clear the dirty flag so that undoing the
  1036.     // first task doesn't result in the "save changes?" alert.
  1037.     
  1038.     if ( ! dirty && aTask )
  1039.         aTask->SetIsFirstTask();
  1040.     
  1041.     dirty = TRUE;    // document has been changed by the task
  1042.     
  1043.     gApplication->SetTask( aTask );    
  1044. }
  1045.  
  1046.  
  1047. /*---------------------------------***  SETSIZE  ***------------------------------------*/
  1048. /*    
  1049.  
  1050. set this window to the width and height passed
  1051. ----------------------------------------------------------------------------------------*/
  1052.  
  1053. void    ZWindow::SetSize( const short width, const short height, const Boolean reDraw )
  1054. {
  1055.     // sets the window's size to the width and height passed, constrained to sizeRect.
  1056.     
  1057.     short    w, h;
  1058.     
  1059.     w  = MIN( sizeRect.right,  MAX( width, sizeRect.left ));
  1060.     h  = MIN( sizeRect.bottom, MAX( height, sizeRect.top ));
  1061.  
  1062.     if (( w != macWindow->portRect.right - macWindow->portRect.left ) ||
  1063.         ( h != macWindow->portRect.bottom - macWindow->portRect.top ))
  1064.     {
  1065.         Focus();
  1066.         if ( reDraw )
  1067.             EraseRect( &macWindow->portRect );
  1068.         
  1069.         SizeWindow( macWindow, w, h, reDraw );
  1070.         WindowResized();
  1071.         
  1072.         if ( reDraw )
  1073.             Draw();
  1074.     }
  1075. }
  1076.  
  1077.  
  1078. /*-----------------------------------***  ZOOM  ***-------------------------------------*/
  1079. /*    
  1080.  
  1081. Zoom this window between the standard and user states. This implements intelligent zoom-
  1082. ing as recommended by the Apple HIG people. It may appear complex and indeed it probably
  1083. is, however, the results are worth it since the zooming of windows almost always does
  1084. exactly the most correct thing for your data- automatically! It also deals with any number
  1085. of multiple monitors. You can always override this if you want something different.
  1086. Based largely on code by Dean Yu, Apple Computer Inc.
  1087. ----------------------------------------------------------------------------------------*/
  1088.  
  1089. #define        kNudgeSlop        2
  1090. #define        kIconAllowance    64
  1091.  
  1092.  
  1093. void    ZWindow::Zoom( const short partCode )
  1094. {
  1095.     RgnHandle    contRgn, strucRgn, scratchRgn;
  1096.     Rect        portRect, crBBox, srBBox, zwBounds, wpOnScreen;
  1097.     short        wfTop, wfLeft, wfBottom, wfRight;
  1098.     long        largestArea = 0;
  1099.     GDHandle    aScreen, targetMonitor;
  1100.     
  1101.     Focus();
  1102.     EraseRect( &macWindow->portRect );
  1103.     
  1104.     // calculate the most intelligent zoom state for the window and set the
  1105.     // standard state to it. The most intelligent state is on the monitor with
  1106.     // the largest area of the window, and that involves the minimum amount of
  1107.     // window movement.
  1108.     
  1109.     if ( partCode == inZoomOut )
  1110.     {
  1111.         GetContentRegion( contRgn = NewRgn());
  1112.         GetStructureRegion( strucRgn = NewRgn());
  1113.         portRect = macWindow->portRect;
  1114.         crBBox = (*contRgn)->rgnBBox;
  1115.         srBBox = (*strucRgn)->rgnBBox;
  1116.         
  1117.         // calculate the window frame size
  1118.         
  1119.         wfTop        = crBBox.top     - srBBox.top;
  1120.         wfLeft        = crBBox.left     - srBBox.left;
  1121.         wfBottom     = srBBox.bottom - crBBox.bottom;
  1122.         wfRight     = srBBox.right     - crBBox.right;
  1123.         
  1124.         // the ideal size for this window is the max sizeRect. For scrollable windows,
  1125.         // this is set according to the bounds, which will give us the expected results
  1126.         // we now need to find the monitor that has the largest portion of the window
  1127.         // intersecting it.
  1128.         
  1129.         scratchRgn = NewRgn();
  1130.         SectRgn( GetGrayRgn(), contRgn, scratchRgn );
  1131.         if (EmptyRgn( scratchRgn ))
  1132.             zwBounds = srBBox;
  1133.         else
  1134.             zwBounds = crBBox;
  1135.         DisposeRgn( scratchRgn );
  1136.         
  1137.         // re-use srBBox for the new standard state rect, initially set to the ideal
  1138.         // window size if we had an infinitely large monitor.
  1139.         
  1140.         GetIdealWindowZoomSize( &srBBox );
  1141.         
  1142.         // walk the device list to determine which monitor the window should be
  1143.         // zoomed to:
  1144.         
  1145.         aScreen = GetDeviceList();
  1146.         
  1147.         while (aScreen)
  1148.         {
  1149.             long wpArea;
  1150.             // find the intersection of the window and the screen
  1151.             
  1152.             SectRect( &zwBounds, &(*aScreen)->gdRect, &wpOnScreen );
  1153.             
  1154.             // find the area of this portion
  1155.             
  1156.             OffsetRect( &wpOnScreen, -wpOnScreen.left, -wpOnScreen.top );
  1157.             wpArea = (long) wpOnScreen.right * (long) wpOnScreen.bottom;
  1158.             
  1159.             // if this is larger than the area found so far, keep track of
  1160.             // the monitor that contains it
  1161.             
  1162.             if (wpArea > largestArea)
  1163.             {
  1164.                 largestArea = wpArea;
  1165.                 targetMonitor = aScreen;
  1166.             }
  1167.             // look at the next monitor in the list
  1168.             
  1169.             aScreen = GetNextDevice( aScreen );
  1170.         }
  1171.         
  1172.         // ok, we have found the monitor we wish to zoom to. Store the monitor's
  1173.         // global rect in the wpOnScreen variable
  1174.         
  1175.         wpOnScreen = (*targetMonitor)->gdRect;
  1176.         
  1177.         // allow for the menubar and desktop icons if it's the main one
  1178.         
  1179.         if (targetMonitor == GetMainDevice())
  1180.         {
  1181.             wpOnScreen.top += GetMBarHeight();
  1182.             wpOnScreen.right -= kIconAllowance;
  1183.         }
  1184.             
  1185.         // OK, we can now calculate the standard rect we wish to zoom to (finally).
  1186.         // We calculate this using srBBox, since that now holds the new std state
  1187.         
  1188.         OffsetRect( &srBBox, crBBox.left, crBBox.top );
  1189.         srBBox.top       -= wfTop;
  1190.         srBBox.left   -= wfLeft;
  1191.         srBBox.right  += wfRight;
  1192.         srBBox.bottom += wfBottom;
  1193.         
  1194.         // this is the ideal size for the window content. See if it needs nudging onto the
  1195.         // monitor
  1196.         
  1197.         SectRect( &srBBox, &wpOnScreen, &zwBounds );
  1198.         if (! EqualRect( &srBBox, &zwBounds ))
  1199.         {
  1200.             // needs to be nudged onto the monitor.
  1201.             
  1202.             short    oH, oV;
  1203.             
  1204.             oH = CalculateOffsetAmount( srBBox.left, srBBox.right,
  1205.                                         zwBounds.left, zwBounds.right,
  1206.                                         wpOnScreen.left, wpOnScreen.right );
  1207.             oV = CalculateOffsetAmount( srBBox.top, srBBox.bottom,
  1208.                                         zwBounds.top, zwBounds.bottom,
  1209.                                         wpOnScreen.top, wpOnScreen.bottom );
  1210.             OffsetRect( &srBBox, oH, oV );
  1211.         }
  1212.         
  1213.         // If this still falls off the screen in any direction, it means that it is too large
  1214.         // for the montior, so it will need to be shrunk down to fit.
  1215.         
  1216.         SectRect( &srBBox, &wpOnScreen, &zwBounds);
  1217.         if (! EqualRect( &srBBox, &zwBounds ))
  1218.         {
  1219.             // nope- still doesn't fit. So shrink it down.
  1220.             
  1221.             if ((srBBox.right - srBBox.left) > (wpOnScreen.right - wpOnScreen.left))
  1222.             {
  1223.                 srBBox.left = wpOnScreen.left + kNudgeSlop;
  1224.                 srBBox.right = wpOnScreen.right - kNudgeSlop;
  1225.             }
  1226.             
  1227.             if ((srBBox.bottom - srBBox.top) > (wpOnScreen.bottom - wpOnScreen.top))
  1228.             {
  1229.                 srBBox.top = wpOnScreen.top + kNudgeSlop;
  1230.                 srBBox.bottom = wpOnScreen.bottom - kNudgeSlop;
  1231.             }
  1232.         }
  1233.         
  1234.         // adjust for the thickness of the frame and set the standard rect
  1235.         
  1236.         srBBox.top       += wfTop;
  1237.         srBBox.left   += wfLeft;
  1238.         srBBox.right  -= wfRight;
  1239.         srBBox.bottom -= wfBottom;
  1240.         
  1241.         SetStdZoomRect( srBBox );
  1242.         
  1243.         DisposeRgn( contRgn );
  1244.         DisposeRgn( strucRgn );
  1245.     }
  1246.     // and.... Zoom!
  1247.  
  1248.     ZoomWindow( macWindow, partCode, FALSE );
  1249.     
  1250.     // notify resize of window
  1251.     
  1252.     WindowResized();
  1253. }
  1254.  
  1255.  
  1256. /*--------------------------***  GETIDEALWINDOWZOOMSIZE  ***----------------------------*/
  1257. /*    
  1258. return the optimum ideal size for a zoomed window. By default this is equal to the
  1259. max size rectangle, but you can override this if you know better.
  1260. ----------------------------------------------------------------------------------------*/
  1261.  
  1262. void    ZWindow::GetIdealWindowZoomSize( Rect* idealSize )
  1263. {
  1264.     idealSize->top = idealSize->left = 0;
  1265.     idealSize->right = sizeRect.right;
  1266.     idealSize->bottom = sizeRect.bottom;    
  1267. }
  1268.  
  1269.  
  1270. /*------------------------------***  SETSTDZOOMRECT  ***--------------------------------*/
  1271. /*    
  1272. set the std rect for zoomable windows. The window zooms to this rect when the zoom box
  1273. is clicked. If the window is not zoomable, this does nothing. The rect is in global coords.
  1274. ----------------------------------------------------------------------------------------*/
  1275.  
  1276. void    ZWindow::SetStdZoomRect( const Rect& aRect )
  1277. {
  1278.     short    v = GetWVariant( macWindow );
  1279.  
  1280.     if (v == zoomDocProc ||
  1281.         v == zoomNoGrow)
  1282.         SetWindowStandardState( macWindow, &aRect );    // using copland macro
  1283. }
  1284.  
  1285. /*------------------------------***  SETUSERZOOMRECT  ***-------------------------------*/
  1286. /*    
  1287. set the user rect for zoomable windows. The window zooms to this rect when the zoom box
  1288. is clicked and zoomed out. The rect is in global coords.
  1289. ----------------------------------------------------------------------------------------*/
  1290.  
  1291. void    ZWindow::SetUserZoomRect( const Rect& aRect )
  1292. {
  1293.     short    v = GetWVariant( macWindow );
  1294.  
  1295.     if (v == zoomDocProc ||
  1296.         v == zoomNoGrow)
  1297.         SetWindowUserState( macWindow, &aRect );        // using copland macro
  1298. }
  1299.  
  1300.  
  1301. #pragma mark -
  1302.  
  1303. /*-----------------------------------***  SAVE  ***-------------------------------------*/
  1304. /*    
  1305.  
  1306. save the contents of the window to a file. This may display the standard file dialog.
  1307. ----------------------------------------------------------------------------------------*/
  1308.  
  1309. Boolean    ZWindow::Save( const Boolean forceSaveAs )
  1310. {
  1311.     // handles the save and save as commands.
  1312.     
  1313.     Boolean        requiresNavPostProcess = FALSE;
  1314.     OSErr        theErr;
  1315.     
  1316.     #if _USE_NAVIGATION_SERVICES
  1317.     NavReplyRecord        navReply;
  1318.     #endif
  1319.     
  1320.     if (! isNamed || forceSaveAs)
  1321.     {
  1322.         // do Save As
  1323.         
  1324.         #if _USE_NAVIGATION_SERVICES
  1325.         
  1326.         if ( gMacInfo.hasNavigationServices )
  1327.         {
  1328.             PickFile( &navReply );
  1329.             
  1330.             if ( navReply.validRecord )
  1331.             {
  1332.                 AEDesc    specDesc;
  1333.                 FInfo    fi;
  1334.         
  1335.                 FailOSErr( AEGetNthDesc( &navReply.selection, 1, typeFSS, NULL, &specDesc ));
  1336.         
  1337.                 BlockMoveData( *specDesc.dataHandle, &macFile, sizeof( FSSpec ));
  1338.             
  1339.                 // to get the type we need to do a FSpGetFInfo, which may return fnfErr
  1340.             
  1341.                 theErr = FSpGetFInfo( &macFile, &fi );
  1342.             
  1343.                 if ( theErr == noErr )
  1344.                     macFType = fi.fdType;
  1345.                     
  1346.                 requiresNavPostProcess = TRUE;
  1347.             }
  1348.             else
  1349.             {
  1350.                 NavDisposeReply( &navReply );
  1351.                 return FALSE;
  1352.             }
  1353.         }
  1354.         else
  1355.         {
  1356.         #endif
  1357.             StandardFileReply    macReply;
  1358.             
  1359.             PickFile( &macReply );
  1360.             
  1361.             if ( macReply.sfGood )
  1362.                 macFile = macReply.sfFile;
  1363.             else
  1364.                 return FALSE;        // user cancelled the save
  1365.         #if _USE_NAVIGATION_SERVICES
  1366.         }
  1367.         #endif
  1368.     }
  1369.     
  1370.     // now do a save with the info.
  1371.     
  1372.     SetWatchCursor();
  1373.     SaveFile();
  1374.     
  1375.     #if _USE_NAVIGATION_SERVICES
  1376.     
  1377.     if ( gMacInfo.hasNavigationServices && requiresNavPostProcess )
  1378.     {
  1379.         NavCompleteSave( &navReply, kNavTranslateInPlace );
  1380.         NavDisposeReply( &navReply );
  1381.     }
  1382.     #endif
  1383.     
  1384.     return TRUE;
  1385. }
  1386.  
  1387.  
  1388. /*---------------------------------***  PICKFILE  ***-----------------------------------*/
  1389. /*    
  1390.  
  1391. display standard file dialog for picking a file for saving. Override if you want custom
  1392. dialog, etc.
  1393.  
  1394. ----------------------------------------------------------------------------------------*/
  1395.  
  1396. void    ZWindow::PickFile( StandardFileReply* macReply )
  1397. {
  1398.     Str31    prompt;
  1399.     Str255     name;
  1400.     
  1401.     GetIndString( prompt, kMiscStrListID, 3 );
  1402.     GetName( name );
  1403.     
  1404.     // make sure that filename is no longer than 31 chars
  1405.     
  1406.     name[0] = MIN( name[0], 31 );
  1407.     
  1408.     // here, we use the "classic" standard file dialog:
  1409.     
  1410.     gWindowManager->DeactivateForDialog( sfPutDialogID );
  1411.     StandardPutFile( prompt, name, macReply );
  1412.     gWindowManager->Activate();
  1413. }
  1414.  
  1415.  
  1416. #if _USE_NAVIGATION_SERVICES
  1417.  
  1418. void    ZWindow::PickFile( NavReplyRecord* navReply )
  1419. {
  1420.     OSErr                theErr;
  1421.     NavDialogOptions    navOptions;
  1422.     
  1423.     FailOSErr( NavGetDefaultDialogOptions( &navOptions ));
  1424.     gApplication->GetName( navOptions.clientName );
  1425.     GetName( navOptions.savedFileName );
  1426.     gWindowManager->Deactivate();
  1427.     
  1428.     theErr = NavPutFile( NULL,
  1429.                          navReply,
  1430.                          &navOptions,
  1431.                          gNavEventHandler,
  1432.                          macFType,
  1433.                          gAppSignature,
  1434.                          (NavCallBackUserData) this );
  1435.                          
  1436.     gWindowManager->Activate();
  1437. }
  1438.  
  1439. #endif
  1440.  
  1441.  
  1442.  
  1443. /*---------------------------------***  SAVEFILE  ***-----------------------------------*/
  1444. /*    
  1445.  
  1446. write out the contents of the window to a file. This may rename the window. Note that you
  1447. need to override this to actually write to a file (using a ZFile, perhaps), then call the
  1448. inherited method to set the name and the state flags.
  1449.  
  1450. ----------------------------------------------------------------------------------------*/
  1451.  
  1452.  
  1453. void    ZWindow::SaveFile()
  1454. {
  1455.     // actually save the window's contents to the file.
  1456.     
  1457.     if ( macFile.vRefNum != kNoFile )
  1458.     {
  1459.         SetTitle( macFile.name );
  1460.         
  1461.         // no longer dirty
  1462.         
  1463.         isNamed = TRUE;
  1464.         dirty = FALSE;
  1465.         
  1466.         // save the window's position to the file
  1467.         
  1468.         SavePosition();
  1469.     }
  1470. }
  1471.  
  1472.  
  1473. /*---------------------------------***  GETNAME  ***------------------------------------*/
  1474. /*    
  1475.  
  1476. return the name of the window
  1477.  
  1478. ----------------------------------------------------------------------------------------*/
  1479.  
  1480. void    ZWindow::GetName( Str255 name )
  1481. {
  1482.     GetWTitle( macWindow, name );
  1483. }
  1484.  
  1485.  
  1486.  
  1487. /*----------------------------------***  REVERT  ***------------------------------------*/
  1488. /*    
  1489.  
  1490. revert the contents of the window to the original file
  1491.  
  1492. ----------------------------------------------------------------------------------------*/
  1493.  
  1494. void    ZWindow::Revert()
  1495. {
  1496.     // revert the contents. By default, this just calls open.
  1497.     
  1498.     #if _USE_NAV_SAVEREVERT_ALERTS
  1499.     if ( gMacInfo.hasNavigationServices )
  1500.     {
  1501.         NavDialogOptions            navOptions;
  1502.         NavAskDiscardChangesResult    navResult;
  1503.         
  1504.         GetName( navOptions.savedFileName );
  1505.         
  1506.         FailOSErr( NavAskDiscardChanges( &navOptions,
  1507.                                          &navResult,
  1508.                                          gNavEventHandler,
  1509.                                          (NavCallBackUserData) this ));
  1510.                                          
  1511.         if ( navResult == kNavAskDiscardChanges )
  1512.         {
  1513.             SetWatchCursor();
  1514.             OpenFile( macFType );
  1515.         }
  1516.     }
  1517.     else
  1518.     {
  1519.     #endif
  1520.     Str31    title;
  1521.     
  1522.     GetName( title );
  1523.     ParamText( title, NULL, NULL, NULL );
  1524.     
  1525.     if ( NotifyAlert( kRevertConfirmAlertID ) == ok )
  1526.     {
  1527.         SetWatchCursor();
  1528.         OpenFile( macFType );
  1529.     }
  1530.     #if _USE_NAV_SAVEREVERT_ALERTS
  1531.     }
  1532.     #endif
  1533. }
  1534.  
  1535.  
  1536. /*---------------------------------***  SETFILE  ***------------------------------------*/
  1537. /*    
  1538.  
  1539. set the filespec for this window to the file passed.
  1540.  
  1541. ----------------------------------------------------------------------------------------*/
  1542.  
  1543. void    ZWindow::SetFile( const FSSpec& aFile )
  1544. {
  1545.     macFile = aFile;
  1546. }
  1547.  
  1548.  
  1549. /*---------------------------------***  OPENFILE  ***-----------------------------------*/
  1550. /*    
  1551.  
  1552. open the file into the window's contents. This will set the name of the window to equal
  1553. the filename
  1554.  
  1555. ----------------------------------------------------------------------------------------*/
  1556.  
  1557. void    ZWindow::OpenFile( const OSType aFileType, Boolean isStationery )
  1558. {
  1559.     // this opens the current file into this window. This function should read the
  1560.     // contents of the file, replacing the current contents.
  1561.     // You should check that the vRefNum of the file spec is not kNoFile.
  1562.     // Call the inherited method to maintain the proper window state variables.
  1563.     
  1564.     if ( macFile.vRefNum != kNoFile )
  1565.     {
  1566.         macFType = aFileType;
  1567.         
  1568.         if ( ! isStationery )
  1569.         {
  1570.             SetTitle(macFile.name);
  1571.             isNamed = TRUE;
  1572.         }
  1573.         
  1574.         stationeryFile = isStationery;
  1575.         
  1576.         if ( IsVisible())
  1577.             PostRefresh();
  1578.             
  1579.         // delete any existing undo task for this window after opening a file,
  1580.         // since it probably contains stale data.
  1581.         
  1582.         ZUndoTask*    task = gApplication->GetUndoTask();
  1583.         
  1584.         if ( task && ( task->GetUndoTarget() == this ))
  1585.             gApplication->SetTask( NULL );
  1586.         
  1587.         dirty = FALSE;
  1588.     }
  1589. }
  1590.  
  1591.  
  1592. /*---------------------------------***  SETTITLE  ***-----------------------------------*/
  1593. /*    
  1594.  
  1595. set the title of the window
  1596. ----------------------------------------------------------------------------------------*/
  1597.  
  1598. void    ZWindow::SetTitle( Str255 aTitle )
  1599. {
  1600.     SetWTitle( macWindow, aTitle );
  1601. }
  1602.  
  1603.  
  1604.  
  1605. /*---------------------------------***  ISVISIBLE  ***----------------------------------*/
  1606. /*    
  1607.  Is the window visible on screen?
  1608. ----------------------------------------------------------------------------------------*/
  1609.  
  1610. Boolean    ZWindow::IsVisible()
  1611. {
  1612.     if ( macWindow )
  1613.         return ((WindowPeek) macWindow)->visible;
  1614.     else
  1615.         return FALSE;
  1616. }
  1617.  
  1618.  
  1619. /*----------------------------------***  ISACTIVE  ***----------------------------------*/
  1620. /*    
  1621.  Is the window currently activated?
  1622. ----------------------------------------------------------------------------------------*/
  1623.  
  1624. Boolean    ZWindow::IsActive()
  1625. {
  1626.     if ( macWindow )
  1627.         return ((WindowPeek) macWindow)->hilited;
  1628.     else
  1629.         return FALSE;
  1630. }
  1631.  
  1632.  
  1633. /*-----------------------------***  GETTITLEBARHEIGHT  ***------------------------------*/
  1634. /*    
  1635.  return the actual height of the window's title bar. This measures it from the regions
  1636.  and is thus totally WDEF safe.
  1637. ----------------------------------------------------------------------------------------*/
  1638.  
  1639. short    ZWindow::GetTitleBarHeight()
  1640. {
  1641.     RgnHandle    sRgn, cRgn;
  1642.     short        tHeight;
  1643.     
  1644.     FailNIL( sRgn = NewRgn());
  1645.     FailNIL( cRgn = NewRgn());
  1646.     
  1647.     GetStructureRegion( sRgn );
  1648.     GetContentRegion( cRgn );
  1649.     
  1650.     tHeight =  (*cRgn)->rgnBBox.top - (*sRgn)->rgnBBox.top;
  1651.     
  1652.     DisposeRgn( sRgn );
  1653.     DisposeRgn( cRgn );
  1654.     
  1655.     return tHeight;
  1656. }
  1657.  
  1658.  
  1659. /*----------------------------***  GETSTRUCTUREREGION  ***------------------------------*/
  1660. /*    
  1661.  copies the window's structure region into the passed region
  1662. ----------------------------------------------------------------------------------------*/
  1663.  
  1664. void    ZWindow::GetStructureRegion( RgnHandle aRgn )
  1665. {
  1666.     FailNILParam( aRgn );
  1667.     
  1668.     WindowPeek    w = ( WindowPeek ) macWindow;
  1669.     
  1670.     Boolean wasFudged = FALSE;
  1671.     short    h, v;
  1672.     Rect    saveUserRect;
  1673.     
  1674.     // if the window isn't visible, the structure region isn't valid, so we have to
  1675.     // make it visible offscreen in order to get the region
  1676.     
  1677.     if ( ! w->visible )
  1678.     {
  1679.         GetWindowUserState( macWindow, &saveUserRect );    
  1680.         GetGlobalPosition( &h, &v ); 
  1681.         
  1682.         MoveWindow( macWindow, h + 10000, v + 100, FALSE );
  1683.         ShowHide( macWindow, TRUE );
  1684.         
  1685.         wasFudged = TRUE;
  1686.     }
  1687.     
  1688.     CopyRgn( w->strucRgn, aRgn );
  1689.     
  1690.     if ( wasFudged )
  1691.     {
  1692.         ShowHide( macWindow, FALSE );    
  1693.         MoveWindow( macWindow, h, v, FALSE );
  1694.         
  1695.         OffsetRgn( aRgn, -10000, -100 );
  1696.         
  1697.         SetWindowUserState( macWindow, &saveUserRect );
  1698.     }
  1699. }
  1700.  
  1701.  
  1702. /*-----------------------------***  GETCONTENTREGION  ***-------------------------------*/
  1703. /*    
  1704.  copies the window's content region into the passed region
  1705. ----------------------------------------------------------------------------------------*/
  1706.  
  1707. void    ZWindow::GetContentRegion( RgnHandle aRgn )
  1708. {
  1709.     FailNILParam( aRgn );
  1710.     
  1711.     WindowPeek    w = ( WindowPeek ) macWindow;
  1712.     
  1713.     Boolean wasFudged = FALSE;
  1714.     short    h, v;
  1715.     Rect    saveUserRect;
  1716.     
  1717.     // if the window isn't visible, the content region isn't valid, so we have to
  1718.     // make it visible offscreen in order to get the region
  1719.     
  1720.     if ( ! w->visible )
  1721.     {
  1722.         GetWindowUserState( macWindow, &saveUserRect );    
  1723.         GetGlobalPosition( &h, &v ); 
  1724.         
  1725.         MoveWindow( macWindow, h + 10000, v + 100, FALSE );
  1726.         ShowHide( macWindow, TRUE );
  1727.         
  1728.         wasFudged = TRUE;
  1729.     }
  1730.     
  1731.     CopyRgn( w->contRgn, aRgn );
  1732.     
  1733.     if ( wasFudged )
  1734.     {
  1735.         ShowHide( macWindow, FALSE );    
  1736.         MoveWindow( macWindow, h, v, FALSE );
  1737.         
  1738.         OffsetRgn( aRgn, -10000, -100 );
  1739.         SetWindowUserState( macWindow, &saveUserRect );
  1740.     }
  1741. }
  1742.  
  1743.  
  1744. /*-------------------------***  GETSTRUCTUREFRAMEBORDER  ***----------------------------*/
  1745. /*    
  1746.  returns in <aRect> the thicknesses of the window borders. <top> is the title bar height,
  1747.  <left> and <right> are the thicknesses of the edges, and <bottom> is the thickness of the
  1748.  bottom.
  1749. ----------------------------------------------------------------------------------------*/
  1750.  
  1751. void    ZWindow::GetStructureFrameBorder( Rect* aRect )
  1752. {
  1753.     RgnHandle    sRgn, cRgn;
  1754.     Rect        s, c;
  1755.     
  1756.     FailNILParam( aRect );
  1757.     
  1758.     FailNIL( sRgn = NewRgn());
  1759.     FailNIL( cRgn = NewRgn());
  1760.     
  1761.     GetStructureRegion( sRgn );
  1762.     GetContentRegion( cRgn );
  1763.     
  1764.     s = (*sRgn)->rgnBBox;
  1765.     c = (*cRgn)->rgnBBox;
  1766.     
  1767.     aRect->top         = c.top    - s.top;
  1768.     aRect->left     = c.left   - s.left;
  1769.     aRect->right     = s.right  - c.right;
  1770.     aRect->bottom     = s.bottom - c.bottom;
  1771.     
  1772.     DisposeRgn( sRgn );
  1773.     DisposeRgn( cRgn );
  1774. }
  1775.  
  1776.  
  1777. /*-----------------------------***  GETGLOBALPOSITION  ***------------------------------*/
  1778. /*    
  1779.  returns the global position of the window on screen
  1780. ----------------------------------------------------------------------------------------*/
  1781.  
  1782. void    ZWindow::GetGlobalPosition( short* hGlobal, short* vGlobal )
  1783. {
  1784.     GrafPtr        savePort;
  1785.     Point        gloc;
  1786.     
  1787.     GetPort( &savePort );
  1788.     SetPort( macWindow );
  1789.     
  1790.     gloc = topLeft( macWindow->portRect );
  1791.     LocalToGlobal( &gloc );
  1792.     
  1793.     SetPort( savePort );
  1794.     
  1795.     *hGlobal = gloc.h;
  1796.     *vGlobal = gloc.v;
  1797. }
  1798.  
  1799.  
  1800. /*-------------------------------***  WRITETOSTREAM  ***--------------------------------*/
  1801. /*    
  1802. write the window state to the stream. You can save an entire window to the stream and
  1803. recreate it exactly later on without needing any resources, etc.
  1804. ----------------------------------------------------------------------------------------*/
  1805.  
  1806. void    ZWindow::WriteToStream( ZStream* aStream )
  1807. {
  1808. #if _MACZOOP_STREAMS
  1809.     ZCommander::WriteToStream( aStream );
  1810.     
  1811.     // save window state info to the stream. This includes its position, title, visible
  1812.     // and floating flags, ID, etc, etc.
  1813.     
  1814.     short    h, v;
  1815.     Str255    title;
  1816.     
  1817.     // write essential data stored in <macWindow> first...
  1818.     
  1819.     aStream->WriteRect( &macWindow->portRect );
  1820.     
  1821.     aStream->WriteChar( IsVisible());
  1822.     aStream->WriteShort( GetWVariant( macWindow ));
  1823.     GetName( title );
  1824.     aStream->WriteString( title );
  1825.     aStream->WriteChar(((WindowPeek) macWindow )->goAwayFlag );
  1826.     
  1827.     // write grafport state
  1828.     
  1829.     aStream->WriteGrafPort( macWindow );
  1830.     
  1831.     // write window's colour table, if there is one
  1832.     
  1833.     AuxWinHandle    awH;
  1834.     
  1835.     if ( GetAuxWin( macWindow, &awH ))
  1836.         aStream->WriteHandle((Handle) (*awH)->awCTable );
  1837.     else
  1838.         aStream->WriteHandle( NULL );
  1839.  
  1840.     // write global window position...
  1841.     
  1842.     GetGlobalPosition( &h, &v );
  1843.     aStream->WriteShort( h );
  1844.     aStream->WriteShort( v );
  1845.     
  1846.     // write various data members...
  1847.     
  1848.     aStream->WriteRect( &sizeRect );
  1849.     aStream->WriteShort( windID );
  1850.     aStream->WriteChar( isNamed );
  1851.     aStream->WriteChar( stationeryFile );
  1852.     aStream->WriteData((Ptr) &macFile, sizeof( FSSpec ));
  1853.     aStream->WriteLong((long) macFType );
  1854.     aStream->WriteChar( printable );
  1855.     aStream->WriteChar( floating );
  1856.     aStream->WriteChar( disableAutoClose );
  1857.     aStream->WriteRect( &zoomSource );
  1858. #endif
  1859. }
  1860.  
  1861.  
  1862. /*------------------------------***  READFROMSTREAM  ***--------------------------------*/
  1863. /*    
  1864. recover the window state from the stream. Normally this is called to actually create a
  1865. window from the stream (i.e. InitZWindow is not called). Thus this uses the stream data
  1866. to make the window and should not be used to change an existing one.
  1867. ----------------------------------------------------------------------------------------*/
  1868.  
  1869. void    ZWindow::ReadFromStream( ZStream* aStream )
  1870. {
  1871. #if _MACZOOP_STREAMS
  1872.     ZCommander::ReadFromStream( aStream );
  1873.     
  1874.     Rect        pr;
  1875.     Boolean        vis, goAway;
  1876.     short        varCode, h, v;
  1877.     long        dLen; 
  1878.     Str255        title;
  1879.     
  1880.     aStream->ReadRect( &pr );
  1881.     aStream->ReadChar((char*) &vis );
  1882.     aStream->ReadShort( &varCode );
  1883.     aStream->ReadString( title );
  1884.     aStream->ReadChar((char*) &goAway );
  1885.     
  1886.     MakeMacWindow( &pr, title, vis, varCode, goAway );
  1887.     
  1888.     // read grafport state
  1889.     
  1890.     aStream->ReadGrafPort( macWindow );
  1891.  
  1892.     // read window colour table
  1893.     
  1894.     WCTabHandle    ct = NULL;
  1895.     
  1896.     aStream->ReadHandle((Handle*) &ct );
  1897.     
  1898.     if ( ct && gMacInfo.supportsColour )
  1899.         SetWinColor( macWindow, ct );
  1900.  
  1901.     // read the rest of our data...
  1902.     
  1903.     aStream->ReadShort( &h );
  1904.     aStream->ReadShort( &v );
  1905.     MoveWindow( macWindow, h, v, FALSE );
  1906.     
  1907.     aStream->ReadRect( &sizeRect );
  1908.     aStream->ReadShort( &windID );
  1909.     aStream->ReadChar((char*) &isNamed );
  1910.     aStream->ReadChar((char*) &stationeryFile );
  1911.     dLen = sizeof( FSSpec );
  1912.     aStream->ReadData((Ptr) &macFile, &dLen );
  1913.     aStream->ReadLong((long*) &macFType );
  1914.     aStream->ReadChar((char*) &printable );
  1915.     aStream->ReadChar((char*) &floating );
  1916.     aStream->ReadChar((char*) &disableAutoClose );
  1917.     aStream->ReadRect( &zoomSource );
  1918.     
  1919.     // register with window manager...
  1920.     
  1921.     gWindowManager->AddWindow( this );
  1922. #endif
  1923. }
  1924.  
  1925. /*------------------------------------***  DRAG  ***------------------------------------*/
  1926. /*    
  1927.  
  1928. initiate a drag from this window
  1929. ----------------------------------------------------------------------------------------*/
  1930.  
  1931. void    ZWindow::Drag( const Point startPt )
  1932. {
  1933.     // this can be called to instigate a drag from this window. When your mouse dragging method
  1934.     // wants to perform a drag, it calls this. This then builds the drag region and drag data
  1935.     // by calling some additional methods. You can override those methods to implement the drag
  1936.     // data, etc you require. <startPt> is in local coordinates, as passed from Click, e.g.
  1937.     
  1938.     DragReference     theDrag;
  1939.     RgnHandle        dragRgn = NULL;
  1940.     unsigned short    diCount;
  1941.     EventRecord        theEvent;
  1942.     
  1943.     if ( MacHasDM())
  1944.     {
  1945.         // make absolutely sure we are the current port, etc.
  1946.         
  1947.         Focus();
  1948.         FailOSErr( NewDrag( &theDrag ));
  1949.         
  1950.         // add data to the drag
  1951.         
  1952.         try
  1953.         {
  1954.             MakeDragData( theDrag );    
  1955.     
  1956.             // if no data was added to the drag (the default case, in fact) do not
  1957.             // bother to do anything else
  1958.             
  1959.             FailOSErr( CountDragItems( theDrag, &diCount ));
  1960.             
  1961.             if ( diCount > 0 )
  1962.             {
  1963.                 // make a drag region
  1964.                 
  1965.                 FailNIL( dragRgn = MakeDragRgn());
  1966.                 
  1967.                 // make a dummy event record
  1968.                 
  1969.                 theEvent.what = mouseDown;
  1970.                 theEvent.where = startPt;
  1971.                 LocalToGlobal(&theEvent.where);
  1972.                 theEvent.when = TickCount();
  1973.                 theEvent.message = 0;
  1974.                 theEvent.modifiers = 0;
  1975.                 
  1976.                 // do that drag manager thang!
  1977.                 
  1978.                 FailOSErr( TrackDrag( theDrag, &theEvent, dragRgn ));
  1979.             }
  1980.         }
  1981.         catch ( OSErr err )
  1982.         {
  1983.             // do not propagate exceptions
  1984.         }
  1985.         
  1986.         DisposeDrag( theDrag );
  1987.         
  1988.         if ( dragRgn )
  1989.             DisposeRgn( dragRgn );
  1990.     }
  1991. }
  1992.  
  1993.  
  1994. /*--------------------------------***  MAKEDRAGRGN  ***---------------------------------*/
  1995. /*    
  1996.  
  1997. create the drag outline. This uses the content rect by default
  1998. ----------------------------------------------------------------------------------------*/
  1999.  
  2000. RgnHandle    ZWindow::MakeDragRgn()
  2001. {
  2002.     // override to build the drag region you require. By default, the drag region is the content
  2003.     // region of the window.
  2004.     
  2005.     Rect        content;
  2006.     RgnHandle    dragRgn, temp;
  2007.     Point        origin = {0,0};
  2008.  
  2009.     FailNIL( dragRgn = NewRgn());
  2010.     FailNIL( temp = NewRgn());
  2011.     
  2012.     GetContentRect( &content );
  2013.     RectRgn( dragRgn, &content );
  2014.     CopyRgn( dragRgn, temp );
  2015.     InsetRgn( temp, 1, 1 );
  2016.     DiffRgn( dragRgn, temp, dragRgn );
  2017.     
  2018.     DisposeRgn( temp );
  2019.     
  2020.     // convert into global corrdinates
  2021.     
  2022.     LocalToGlobal( &origin );
  2023.     OffsetRgn( dragRgn, origin.h, origin.v );
  2024.     
  2025.     return dragRgn;
  2026. }
  2027.  
  2028.  
  2029. /*---------------------------------***  DRAGHILITE  ***---------------------------------*/
  2030. /*    
  2031.  
  2032. hilite the window in response to a drag over it
  2033. ----------------------------------------------------------------------------------------*/
  2034.  
  2035. void    ZWindow::DragHilite( const Boolean state, const DragReference theDrag)
  2036. {
  2037.     // hilites the window. This uses the drag manager's default hiliting.
  2038.     
  2039.     RgnHandle    dragHiliteRgn;
  2040.     Rect        content;
  2041.     
  2042.     Focus();
  2043.     
  2044.     if ( state )
  2045.     {
  2046.         // make the hilite region
  2047.         
  2048.         FailNIL( dragHiliteRgn = NewRgn());    
  2049.     
  2050.         GetContentRect( &content );
  2051.         RectRgn( dragHiliteRgn, &content );
  2052.         
  2053.         (void) ShowDragHilite( theDrag, dragHiliteRgn, TRUE );
  2054.         
  2055.         DisposeRgn( dragHiliteRgn );
  2056.     }
  2057.     else
  2058.         (void) HideDragHilite( theDrag );
  2059.  
  2060. }
  2061.  
  2062. /*----------------------------***  INSTALLDRAGHANDLERS  ***-----------------------------*/
  2063. /*    
  2064.  
  2065. install the procs that call this during a drag
  2066.  
  2067. ----------------------------------------------------------------------------------------*/
  2068.  
  2069. void    ZWindow::InstallDragHandlers()
  2070. {
  2071.     // set up the drag handler proc to call this object when a drag occurs over this window. The
  2072.     // window's refCon field contains the object reference, so the handler can find this object.
  2073.     
  2074.     FailOSErr( InstallTrackingHandler( gDragTrackProc,      macWindow, 0L ));
  2075.     FailOSErr( InstallReceiveHandler ( gDragReceiveProc, macWindow, 0L ));    
  2076. }
  2077.  
  2078.  
  2079. /*----------------------------***  REMOVEDRAGHANDLERS  ***------------------------------*/
  2080. /*    
  2081.  
  2082. get rid of the handlers. This is called by the destructor
  2083.  
  2084. ----------------------------------------------------------------------------------------*/
  2085.  
  2086. void    ZWindow::RemoveDragHandlers()
  2087. {
  2088.     // removes the drag handlers when the window is deleted
  2089.     
  2090.     OSErr    theErr;
  2091.     
  2092.     theErr = RemoveTrackingHandler( gDragTrackProc,   macWindow );    
  2093.     theErr = RemoveReceiveHandler ( gDragReceiveProc, macWindow );    
  2094. }
  2095.  
  2096.  
  2097.  
  2098. /*--------------------------------***  DROPHANDLER  ***---------------------------------*/
  2099. /*    
  2100.  
  2101. unpacks the data from an accepted drag and passes it to the Drop method.
  2102.  
  2103. ----------------------------------------------------------------------------------------*/
  2104.  
  2105. void    ZWindow::DropHandler( const DragReference theDrag )
  2106. {
  2107.     // method to dispatch drops from the drag manager. This unpacks the drag data, and for
  2108.     // each flavour that the AcceptsFlavour method returns TRUE for, will call Drop with the
  2109.     // data of the item.
  2110.     
  2111.     unsigned short    dragItemCount, i;
  2112.     unsigned short    dragFlavourCount, f;
  2113.     ItemReference    iRef;
  2114.     FlavorType        theFlavour;
  2115.     Boolean            atLeastOneAccepted = FALSE;
  2116.     Size            dataSize;
  2117.     Ptr                theData = NULL;
  2118.     
  2119.     DragHilite( FALSE, theDrag );
  2120.     FailOSErr( CountDragItems( theDrag, &dragItemCount ));
  2121.     
  2122.     SetBeachBallCursor();
  2123.     
  2124.     for ( i = 1; i <= dragItemCount; i++ )
  2125.     {
  2126.         // get the item
  2127.         
  2128.         FailOSErr( GetDragItemReferenceNumber( theDrag, i, &iRef ));    
  2129.     
  2130.         // count the flavours in the item
  2131.         
  2132.         FailOSErr( CountDragItemFlavors( theDrag, iRef, &dragFlavourCount ));
  2133.         
  2134.         // for each flavour, if we can accept the flavour, unpack it and pass the data
  2135.         // to the drop method.
  2136.         
  2137.         for ( f = 1; f <= dragFlavourCount; f++ )
  2138.         {
  2139.             FailOSErr( GetFlavorType( theDrag, iRef, f, &theFlavour ));
  2140.         
  2141.             if ( AcceptsFlavour( theFlavour ))
  2142.             {
  2143.                 // get the data for this object
  2144.                 
  2145.                 FailOSErr( GetFlavorDataSize( theDrag, iRef, theFlavour, &dataSize ));
  2146.                 
  2147.                 // create a buffer big enough to hold the object
  2148.                 
  2149.                 FailNIL( theData = NewPtr( dataSize ));
  2150.                 
  2151.                 // get the data into the buffer
  2152.                 
  2153.                 try
  2154.                 {
  2155.                     FailOSErr( GetFlavorData( theDrag, iRef, theFlavour, theData, &dataSize, 0L ));
  2156.                 
  2157.                     // call the method to handle the drop
  2158.                     
  2159.                     Drop( theFlavour, theData, dataSize );    
  2160.                 }
  2161.                 catch( OSErr err )
  2162.                 {
  2163.                     if ( theData )
  2164.                         DisposePtr( theData );
  2165.                         
  2166.                     theData = NULL;
  2167.                     
  2168.                     throw err;    
  2169.                 }    
  2170.                 if ( theData )
  2171.                     DisposePtr( theData );
  2172.                     
  2173.                 theData = NULL;
  2174.                 atLeastOneAccepted = TRUE;
  2175.             }
  2176.         }
  2177.     }
  2178.     
  2179.     // if nothing in this drag was accepted (unlikely???), throw an error
  2180.     // so that the drag manager gives the right feedback
  2181.     
  2182.     if (! atLeastOneAccepted)
  2183.         FailOSErr( paramErr );
  2184. }
  2185.  
  2186.  
  2187.  
  2188. /*-------------------------------***  TRACKTHEDRAG  ***---------------------------------*/
  2189. /*    
  2190.  
  2191. dispatches tracking messages to the appropriate method
  2192. ----------------------------------------------------------------------------------------*/
  2193.  
  2194.  
  2195. void    ZWindow::DragDispatch( const DragTrackingMessage theMessage, const DragReference theDrag )
  2196. {
  2197.     // this method handles the tracking of a drag within this window. It calls various other
  2198.     // methods to implement its behaviour- normally you would override those where necessary
  2199.     // rather than this, which is quite low-level.
  2200.     
  2201.     switch ( theMessage )
  2202.     {    
  2203.         case kDragTrackingEnterHandler:
  2204.             EnteredHandler( theDrag );
  2205.             break;
  2206.         
  2207.         case kDragTrackingEnterWindow:
  2208.             EnteredWindow( theDrag );
  2209.             break;
  2210.         
  2211.         case kDragTrackingInWindow:
  2212.             InWindow( theDrag );
  2213.             break;
  2214.         
  2215.         case kDragTrackingLeaveWindow:
  2216.             LeftWindow( theDrag );
  2217.             break;
  2218.         
  2219.         case kDragTrackingLeaveHandler:
  2220.             LeftHandler( theDrag );
  2221.             break;
  2222.     }
  2223. }
  2224.  
  2225.  
  2226. /*-------------------------------***  ENTEREDWINDOW  ***--------------------------------*/
  2227. /*    
  2228.  
  2229. the window was made the target of the drag. This hilites it if any flavour in the drag is
  2230. acceptable.
  2231. ----------------------------------------------------------------------------------------*/
  2232.  
  2233. void    ZWindow::EnteredWindow( const DragReference theDrag)
  2234. {
  2235.     // the drag has enetered this window. If the window accepts any of the flavours in the drag,
  2236.     // hilite the window.
  2237.  
  2238.     unsigned short    dragItemCount;
  2239.     unsigned short    dragFlavourCount;
  2240.     ItemReference    iRef;
  2241.     FlavorType        theFlavour;
  2242.     
  2243.     
  2244.     
  2245.     FailOSErr(CountDragItems(theDrag, &dragItemCount));
  2246.     
  2247.     if (dragItemCount)
  2248.     {
  2249.         do
  2250.         {
  2251.             // for each drag item, count the flavours
  2252.             
  2253.             FailOSErr(GetDragItemReferenceNumber(theDrag, dragItemCount, &iRef));
  2254.             FailOSErr(CountDragItemFlavors(theDrag, iRef, &dragFlavourCount));
  2255.             
  2256.             // for each flavour, see if we can accept it. As soon as we get one that we can
  2257.             // handle, we hilite the window and exit.
  2258.             
  2259.             do
  2260.             {
  2261.                 FailOSErr(GetFlavorType(theDrag, iRef, dragFlavourCount, &theFlavour));    
  2262.             
  2263.                 if (AcceptsFlavour(theFlavour))
  2264.                 {
  2265.                     DragHilite(TRUE, theDrag);
  2266.                     return;
  2267.                 }
  2268.             }
  2269.             while(--dragFlavourCount);
  2270.         }
  2271.         while(--dragItemCount);
  2272.     }
  2273. }
  2274.  
  2275. /*---------------------------------***  LEFTWINDOW  ***---------------------------------*/
  2276. /*    
  2277.  
  2278. the drag is no longer in this window. This unhilites the drag here.
  2279. ----------------------------------------------------------------------------------------*/
  2280.  
  2281. void    ZWindow::LeftWindow( const DragReference theDrag)
  2282. {
  2283.     // Ladies and Gentlemen, the drag has left the window. Please leave in an orderly fashion.
  2284.     
  2285.     DragHilite( FALSE, theDrag );
  2286. }
  2287.  
  2288.  
  2289.  
  2290.  
  2291.  
  2292. #pragma mark -
  2293. /*---------------------------------******************----------------------------------*/
  2294.  
  2295. static short CalculateOffsetAmount(short idealStartPoint, short idealEndPoint, short idealOnScreenStartPoint,
  2296.                             short idealOnScreenEndPoint, short screenEdge1, short screenEdge2)
  2297. {
  2298.     short    offsetAmount;
  2299.  
  2300.     // First check to see if the window fits on the screen in this dimension.
  2301.     if ((idealStartPoint < screenEdge1) && (idealEndPoint > screenEdge2))
  2302.         offsetAmount = 0;
  2303.     else
  2304.     {
  2305.     
  2306.         // Find out how much of the window lies off this screen by subtracting the amount of the window
  2307.         // that is on the screen from the size of the entire window in this dimension. If the window
  2308.         // is completely offscreen, the offset amount is going to be the distance from the ideal
  2309.         // starting point to the first edge of the screen.
  2310.         if ((idealOnScreenStartPoint - idealOnScreenEndPoint) == 0)
  2311.         {
  2312.             // See if the window is lying to the left or above the screen
  2313.             if (idealEndPoint < screenEdge1)
  2314.                 offsetAmount = screenEdge1 - idealStartPoint + kNudgeSlop;
  2315.             else
  2316.             // Otherwise, it’s below or to the right of the screen
  2317.                 offsetAmount = screenEdge2 - idealEndPoint - kNudgeSlop;
  2318.         }
  2319.         else
  2320.         {
  2321.             // Window is already partially or completely on the screen
  2322.             offsetAmount = (idealEndPoint - idealStartPoint) -
  2323.                             (idealOnScreenEndPoint - idealOnScreenStartPoint);
  2324.     
  2325.             // If we are offscreen a little, move the window in a few more pixels from the edge of the screen.
  2326.             if (offsetAmount != 0)
  2327.                 offsetAmount += kNudgeSlop;
  2328.             
  2329.             // Check to see which side of the screen the window was falling off of, so that it can be
  2330.             // nudged in the opposite direction.
  2331.             if (idealEndPoint > screenEdge2)
  2332.                 offsetAmount = -offsetAmount;
  2333.         }
  2334.     }
  2335.     
  2336.     return offsetAmount;
  2337. }
  2338.  
  2339.  
  2340. /*--------------------------------*********************---------------------------------*/
  2341. /*    
  2342.  
  2343. static functions follow. Do not modify them directly- all features can be acessed by
  2344. overriding the appropriate methods.
  2345.  
  2346. ----------------------------------------------------------------------------------------*/
  2347.  
  2348. static pascal OSErr    ZWTrackingHandler(DragTrackingMessage theMsg, WindowPtr theWindow, void* refCon,
  2349.                                     DragReference theDrag)
  2350. {
  2351.     ZWindow*    zdWindow = NULL;
  2352.     OSErr        theErr = noErr;
  2353.     
  2354.     // get the object
  2355.     
  2356.     if ( theWindow )
  2357.         zdWindow = GetZWindow( theWindow );
  2358.  
  2359.     try
  2360.     {
  2361.         FailNIL( zdWindow );
  2362.         
  2363.         zdWindow->DragDispatch( theMsg, theDrag );
  2364.     }
  2365.     catch( OSErr err )
  2366.     {
  2367.         theErr = err;
  2368.     }
  2369.     
  2370.     return theErr;
  2371. }
  2372.  
  2373.  
  2374. /*--------------------------------*********************---------------------------------*/
  2375.  
  2376. static pascal OSErr    ZWDropHandler( WindowPtr theWindow, void* refCon, DragReference theDrag )
  2377. {
  2378.     ZWindow*    zdWindow = NULL;
  2379.     OSErr        theErr = noErr;
  2380.     // get the object
  2381.     
  2382.     if ( theWindow )
  2383.         zdWindow = GetZWindow( theWindow );
  2384.  
  2385.     try
  2386.     {
  2387.         FailNIL( zdWindow );
  2388.         
  2389.         zdWindow->DropHandler( theDrag );
  2390.     }
  2391.     catch( OSErr err )
  2392.     {
  2393.         SysBeep(1);
  2394.         theErr = err;
  2395.     }
  2396.     
  2397.     return theErr;
  2398. }
  2399.  
  2400. /*--------------------------------*********************---------------------------------*/
  2401.  
  2402.  
  2403.  
  2404.